package com.gxc.string;

import java.util.HashMap;
import java.util.Map;

/**
 * 65. 有效数字

 * 给定一个字符串 s ，返回 s 是否是一个 有效数字。
 *
 * 例如，下面的都是有效数字："2", "0089", "-0.1", "+3.14", "4.", "-.9", "2e10", "-90E3", "3e+7", "+6e-1", "53.5e93", "-123.456e789"，而接下来的不是："abc", "1a", "1e", "e3", "99e2.5", "--6", "-+3", "95a54e53"。
 *
 * 一般的，一个 有效数字 可以用以下的规则之一定义：
 *
 * 一个 整数 后面跟着一个 可选指数。
 * 一个 十进制数 后面跟着一个 可选指数。
 *
 * 一个 整数 定义为一个 可选符号 '-' 或 '+' 后面跟着 数字。
 *
 * 一个 十进制数 定义为一个 可选符号 '-' 或 '+' 后面跟着下述规则：
 *
 * 数字 后跟着一个 小数点 .。
 * 数字 后跟着一个 小数点 . 再跟着 数位。
 * 一个 小数点 . 后跟着 数位。
 *
 * 指数 定义为指数符号 'e' 或 'E'，后面跟着一个 整数。
 *
 * 数字 定义为一个或多个数位。
 */
public class IsNumber {

    public static void main(String[] args) {
        System.out.println(handle(".2"));
        System.out.println(handle("2"));
        System.out.println(handle("0089"));
        System.out.println(handle("-0.1"));
        System.out.println(handle("+3.14"));
        System.out.println(handle("-.9"));
        System.out.println(handle("2e10"));
        System.out.println(handle("-90E3"));
        System.out.println(handle("3e+7"));
        System.out.println(handle("+6e-1"));
        System.out.println(handle("53.5e93"));
        System.out.println(handle("-123.456e789"));
        System.out.println("--------------");
        System.out.println(handle("abc"));
        System.out.println(handle("1a"));
        System.out.println(handle("1e"));
        System.out.println(handle("e3"));
        System.out.println(handle("99e2.5"));
        System.out.println(handle("--6"));
        System.out.println(handle("-+3"));
        System.out.println(handle("95a54e53"));
        System.out.println(handle("."));
        System.out.println(handle(".e1"));
        System.out.println(handle("4e+"));
        System.out.println(handle("+."));
    }

    //有限状态机  状态 和  事件
    public static boolean handle(String s) {
        //状态转换事件
        Map<State2, Map<CharType2, State2>> transfer = new HashMap<>();
        //初始状态 后续可选 数字  .  -+
        Map<CharType2, State2> initMap = new HashMap<>();
        initMap.put(CharType2.NUMBER, State2.INTEGER);
        initMap.put(CharType2.SIGN, State2.SIGN_WITHOUT_NUMBER);
        initMap.put(CharType2.POINT, State2.POINT_WITHOUT_NUMBER);
        transfer.put(State2.INITIAL, initMap);
        //数字状态  后续可选 数字  . e
        Map<CharType2, State2> intMap = new HashMap<>();
        intMap.put(CharType2.NUMBER, State2.INTEGER);
        intMap.put(CharType2.POINT, State2.POINT_END);
        intMap.put(CharType2.EXP, State2.EXP_WITHOUT_NUMBER);
        transfer.put(State2.INTEGER, intMap);
        //-+状态  后续可选  数字  .
        Map<CharType2, State2> signWithoutNumberMap = new HashMap<>();
        signWithoutNumberMap.put(CharType2.NUMBER, State2.INTEGER);
        signWithoutNumberMap.put(CharType2.POINT, State2.POINT_WITHOUT_NUMBER);
        transfer.put(State2.SIGN_WITHOUT_NUMBER, signWithoutNumberMap);
        //.状态  后续可选  数字
        Map<CharType2, State2> pointWithoutNumberMap = new HashMap<>();
        pointWithoutNumberMap.put(CharType2.NUMBER, State2.POINT);
        transfer.put(State2.POINT_WITHOUT_NUMBER, pointWithoutNumberMap);
        //2.状态  后续可选  数字
        Map<CharType2, State2> pointEndMap = new HashMap<>();
        pointEndMap.put(CharType2.NUMBER, State2.POINT);
        pointEndMap.put(CharType2.EXP, State2.EXP_WITHOUT_NUMBER);
        transfer.put(State2.POINT_END, pointEndMap);
        //e E 状态  后续可选  数字 -+
        Map<CharType2, State2> expWithoutNumberMap = new HashMap<>();
        expWithoutNumberMap.put(CharType2.NUMBER, State2.EXP);
        expWithoutNumberMap.put(CharType2.SIGN, State2.EXP_SIGN);
        transfer.put(State2.EXP_WITHOUT_NUMBER, expWithoutNumberMap);
        //.1 状态  后续可选  数字
        Map<CharType2, State2> pointMap = new HashMap<>();
        pointMap.put(CharType2.NUMBER, State2.POINT);
        pointMap.put(CharType2.EXP, State2.EXP_WITHOUT_NUMBER);
        transfer.put(State2.POINT, pointMap);
        //1e1 状态  后续可选  数字
        Map<CharType2, State2> expMap = new HashMap<>();
        expMap.put(CharType2.NUMBER, State2.EXP);
        transfer.put(State2.EXP, expMap);
        //1e1 状态  后续可选  数字
        Map<CharType2, State2> expSignMap = new HashMap<>();
        expSignMap.put(CharType2.NUMBER, State2.EXP);
        transfer.put(State2.EXP_SIGN, expSignMap);

        int l = s.length();
        State2 curState = State2.INITIAL;
        for (int i = 0; i < l; i++) {
            CharType2 charType2 = toChartype(s.charAt(i));
            if (transfer.get(curState).containsKey(charType2)) {
                //根据当前状态和参数触发事件转换状态
                curState = transfer.get(curState).get(charType2);
            } else {
                return false;
            }
        }
        return curState == State2.INTEGER || curState == State2.POINT ||
                curState == State2.EXP || curState == State2.POINT_END;
    }

    private static CharType2 toChartype(char c) {
        if (c>='0' && c<='9') return CharType2.NUMBER;
        else if (c == '-' || c == '+') return CharType2.SIGN;
        else if (c == '.') return CharType2.POINT;
        else if (c == 'e' || c == 'E') return CharType2.EXP;
        return CharType2.ILLEGALITY;
    }

    enum State2 {
        INITIAL,
        INTEGER,
        POINT_WITHOUT_NUMBER,
        SIGN_WITHOUT_NUMBER,
        POINT,
        EXP_WITHOUT_NUMBER,
        POINT_END,
        EXP,
        EXP_SIGN
    }

    enum CharType2 {
        NUMBER,
        SIGN,
        POINT,
        EXP,
        ILLEGALITY
    }

    class Solution {
        public boolean isNumber(String s) {
            Map<State, Map<CharType, State>> transfer = new HashMap<State, Map<CharType, State>>();
            Map<CharType, State> initialMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
                put(CharType.CHAR_POINT, State.STATE_POINT_WITHOUT_INT);
                put(CharType.CHAR_SIGN, State.STATE_INT_SIGN);
            }};
            transfer.put(State.STATE_INITIAL, initialMap);
            Map<CharType, State> intSignMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
                put(CharType.CHAR_POINT, State.STATE_POINT_WITHOUT_INT);
            }};
            transfer.put(State.STATE_INT_SIGN, intSignMap);
            Map<CharType, State> integerMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_INTEGER);
                put(CharType.CHAR_EXP, State.STATE_EXP);
                put(CharType.CHAR_POINT, State.STATE_POINT);
            }};
            transfer.put(State.STATE_INTEGER, integerMap);
            Map<CharType, State> pointMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
                put(CharType.CHAR_EXP, State.STATE_EXP);
            }};
            transfer.put(State.STATE_POINT, pointMap);
            Map<CharType, State> pointWithoutIntMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
            }};
            transfer.put(State.STATE_POINT_WITHOUT_INT, pointWithoutIntMap);
            Map<CharType, State> fractionMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_FRACTION);
                put(CharType.CHAR_EXP, State.STATE_EXP);
            }};
            transfer.put(State.STATE_FRACTION, fractionMap);
            Map<CharType, State> expMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
                put(CharType.CHAR_SIGN, State.STATE_EXP_SIGN);
            }};
            transfer.put(State.STATE_EXP, expMap);
            Map<CharType, State> expSignMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
            }};
            transfer.put(State.STATE_EXP_SIGN, expSignMap);
            Map<CharType, State> expNumberMap = new HashMap<CharType, State>() {{
                put(CharType.CHAR_NUMBER, State.STATE_EXP_NUMBER);
            }};
            transfer.put(State.STATE_EXP_NUMBER, expNumberMap);

            int length = s.length();
            State state = State.STATE_INITIAL;

            for (int i = 0; i < length; i++) {
                CharType type = toCharType(s.charAt(i));
                if (!transfer.get(state).containsKey(type)) {
                    return false;
                } else {
                    state = transfer.get(state).get(type);
                }
            }
            return state == State.STATE_INTEGER || state == State.STATE_POINT || state == State.STATE_FRACTION || state == State.STATE_EXP_NUMBER || state == State.STATE_END;
        }

        public CharType toCharType(char ch) {
            if (ch >= '0' && ch <= '9') {
                return CharType.CHAR_NUMBER;
            } else if (ch == 'e' || ch == 'E') {
                return CharType.CHAR_EXP;
            } else if (ch == '.') {
                return CharType.CHAR_POINT;
            } else if (ch == '+' || ch == '-') {
                return CharType.CHAR_SIGN;
            } else {
                return CharType.CHAR_ILLEGAL;
            }
        }


    }

    enum State {
        STATE_INITIAL,
        STATE_INT_SIGN,
        STATE_INTEGER,
        STATE_POINT,
        STATE_POINT_WITHOUT_INT,
        STATE_FRACTION,
        STATE_EXP,
        STATE_EXP_SIGN,
        STATE_EXP_NUMBER,
        STATE_END
    }

    enum CharType {
        CHAR_NUMBER,
        CHAR_EXP,
        CHAR_POINT,
        CHAR_SIGN,
        CHAR_ILLEGAL
    }

}
